﻿#region Imports

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using N2;
using N2.Details;
using N2.Edit;
using N2.Resources;

#endregion

namespace AWS.N2CMS.Tags
{
    public class EditableTagsAttribute : EditableListControlAttribute
    {
        private LinkButton _btnAddTag;
        private TextBox _tbTagName;

        public EditableTagsAttribute(string title, int sortOrder, bool fancy)
            : base(title, sortOrder)
        {
            Fancy = fancy;
        }

        public bool Fancy { get; set; }

        protected override ListControl CreateEditor()
        {
            return new ListBox {SelectionMode = ListSelectionMode.Multiple};
        }

        protected override Control AddEditor(Control container)
        {
            #region Add ListBox

            ListControl ddl = CreateEditor();
            ddl.ID = Name;

            ddl.Items.AddRange(GetListItems());
            container.Controls.Add(ddl);

            #endregion

            #region Register Scripts and Styles

            if (Fancy)
            {
                //Register.JavaScript(container.Page, "~/N2/Resources/Js/jquery.ui.ashx");
                Register.JavaScript(container.Page, "~/Content/Plugins/Tags/jquery.multiselect.min.js");
                Register.StyleSheet(container.Page, "~/Content/Plugins/Tags/jquery.ui.css");
                Register.StyleSheet(container.Page, "~/Content/Plugins/Tags/jquery.multiselect.css");

                string script = "$('#" + ddl.ClientID + "').multiSelect();";
                Register.JavaScript(container.Page, script, ScriptOptions.DocumentReady);
            }

            #endregion

            #region Add "add new tags" controls

            var divContainer = new HtmlGenericControl("div");
            divContainer.Style.Add("margin-left", "115px;");
            divContainer.Style.Add("margin-top", "5px;");
            divContainer.Style.Add("margin-bottom", "5px;");

            _tbTagName = new TextBox
                             {
                                 ID = "tbTagName",
                                 ValidationGroup = "AddTag"
                             };

            _btnAddTag = new LinkButton
                             {
                                 ID = "btnAddTag",
                                 Text = "Add Tag",
                                 OnClientClick =
                                     "return confirm('Adding a new tag till cause the page to refresh, causing any unsaved data to be lost. Are you sure you want to add a tag?');",
                                 ValidationGroup = "AddTag"
                             };
            _btnAddTag.Click += AddTag;

            //var validator = new RequiredFieldValidator
            //                    {
            //                        ValidationGroup = "AddTag",
            //                        ErrorMessage = "*",
            //                        ControlToValidate = _tbTagName.ID,
            //                    };

            divContainer.Controls.Add(_tbTagName);
            //divContainer.Controls.Add(validator);
            divContainer.Controls.Add(_btnAddTag);
            container.Controls.Add(divContainer);

            #endregion

            return ddl;
        }

        protected void AddTag(object sender, EventArgs e)
        {
            string tagName = _tbTagName.Text.Trim();

            if (string.IsNullOrEmpty(tagName)) return;

            IList<Tag> tags = Find.Items.Where.Type.Eq(typeof (Tag)).And.Name.Eq(tagName.ToLower()).Select<Tag>();

            if (tags.Count > 0) return;

            //the tag doesn't exist, do lets add it.
            var tag = Context.Current.Definitions.CreateInstance<Tag>(null);
            tag.Name = tagName.ToLower();
            tag.Title = tagName;

            Context.Persister.Save(tag);

            var selectionUtility = new SelectionUtility(HttpContext.Current.Request, Context.Current);

            HttpContext.Current.Response.Redirect(
                Context.Current.EditManager.GetEditExistingItemUrl(selectionUtility.SelectedItem));
        }

        protected override ListItem[] GetListItems()
        {
            IList<Tag> tags = Find.Items.Where.Type.Eq(typeof (Tag)).Select<Tag>();
            return tags.Select(x => new ListItem(x.Title, x.ID.ToString())).ToArray();
        }

        public override bool UpdateItem(ContentItem item, Control editor)
        {
            var ddl = editor as ListControl;
            IList<Tag> currentTags = GetValues(item);
            bool updated = false;
            foreach (var listItem in ddl.Items.Cast<ListItem>().Where(listItem => listItem.Selected))
            {
                int value = int.Parse(listItem.Value);
                if (!currentTags.Any(x => x.ID.Equals(value)))
                {
                    //An new item is selected
                    updated = true;
                    currentTags.Add(Find.Items.Where.Type.Eq(typeof (Tag)).And.ID.Eq(value).Select<Tag>().First());
                }
            }
            var toRemove = new List<Tag>();
            foreach (var currentTag in currentTags)
            {
                int id = currentTag.ID;
                if (ddl.Items.Cast<ListItem>().Any(x => x.Value == id.ToString() && !x.Selected))
                {
                    //an item has been removed
                    updated = true;
                    toRemove.Add(currentTag);
                }
            }
            foreach (var deleted in toRemove)
            {
                currentTags.Remove(deleted);
            }
            if (updated)
            {
                DetailCollection detailCollection = item.GetDetailCollection(Name, true);
                foreach (var currentTag in currentTags)
                {
                    if (!detailCollection.Contains(currentTag))
                    {
                        detailCollection.Add(currentTag);
                    }
                }
                var detailsToRemove = new List<ContentDetail>();
                foreach (var detailValue in detailCollection.Details)
                {
                    ContentDetail value = detailValue;
                    if (!currentTags.Any(x => value.Value.Equals(x)))
                    {
                        detailsToRemove.Add(detailValue);
                    }
                }
                foreach (var detailToRemove in detailsToRemove)
                {
                    detailCollection.Details.Remove(detailToRemove);
                }
            }
            return updated;
        }

        public IList<Tag> GetValues(ContentItem item)
        {
            DetailCollection details = item.GetDetailCollection(Name, true);
            var tags = new List<Tag>();
            foreach (
                var detail in details.Details.Where(detail => detail.ValueType.Equals(typeof (ContentItem))))
            {
                if (((LinkDetail) detail).LinkedItem.GetType().Equals(typeof (Tag)))
                {
                    tags.Add((detail as LinkDetail).LinkedItem as Tag);
                }
                else
                {
                    throw new N2Exception("Why is this detail not a tag?");
                }
            }
            return tags;
        }

        protected override object GetValue(ListControl ddl)
        {
            List<string> names = (from ListItem item in ddl.Items where item.Selected select item.Value).ToList();
            if (names.Any())
            {
                IList<Tag> tags = Find.Items.Where.Name.In(names.ToArray()).Select<Tag>();
                return tags;
            }
            return new List<Tag>();
        }

        public override void UpdateEditor(ContentItem item, Control editor)
        {
            var lb = editor as ListBox;
            IList<Tag> currentTags = GetValues(item);
            foreach (ListItem listItem in lb.Items)
            {
                ListItem item1 = listItem;
                if (currentTags.Any(x => x.ID == int.Parse(item1.Value)))
                {
                    listItem.Selected = true;
                }
            }
        }
    }
}